{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# HM2 Biomass potential grid search with natural observations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# import the libraries\n",
    "import ee\n",
    "import pandas as pd\n",
    "import os\n",
    "import numpy as np\n",
    "import random\n",
    "from random import sample\n",
    "import itertools \n",
    "import geopandas as gpd\n",
    "from sklearn.metrics import r2_score\n",
    "from termcolor import colored # this is allocate colour and fonts type for the print title and text\n",
    "from IPython.display import display, HTML"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "#check the working directory of local drive for Grid search result table loading\n",
    "# os.getcwd()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# initialize the earth engine API\n",
    "ee.Initialize()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STEP 1 Data preperation and objects definition"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['SpawnDensity']\n"
     ]
    }
   ],
   "source": [
    "# load the biomass map \n",
    "# transfer biomass to carbon stock with the factor 0.5\n",
    "biomassDensityMapRaw = ee.Image(\"users/leonidmoore/ForestBiomass/SpawnMap/Spawn_Harmonized_AGB_density_Map_1km\").select('agb')\n",
    "# filter out the points with 0 carbon density in Spawn's carbon stock density map\n",
    "biomassDensityMap = biomassDensityMapRaw.mask(biomassDensityMapRaw.gt(0)).rename('SpawnDensity')\n",
    "print(biomassDensityMap.bandNames().getInfo())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4124\n"
     ]
    }
   ],
   "source": [
    "# do random subsampling\n",
    "exampleSamplePoints = ee.FeatureCollection(\"users/leonidmoore/ForestBiomass/SpawnMap/GridSampleShapefiles/HM2_Gridsubsampled_Natural_Seed_0\")\n",
    "print(exampleSamplePoints.size().getInfo())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# define the boundary geography reference\n",
    "unboundedGeo = ee.Geometry.Polygon([-180, 88, 0, 88, 180, 88, 180, -88, 0, -88, -180, -88], None, False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['Aridity_Index', 'CHELSA_Annual_Mean_Temperature', 'CHELSA_Annual_Precipitation', 'CHELSA_Isothermality', 'CHELSA_Max_Temperature_of_Warmest_Month', 'CHELSA_Mean_Diurnal_Range', 'CHELSA_Mean_Temperature_of_Coldest_Quarter', 'CHELSA_Mean_Temperature_of_Driest_Quarter', 'CHELSA_Mean_Temperature_of_Warmest_Quarter', 'CHELSA_Mean_Temperature_of_Wettest_Quarter', 'CHELSA_Min_Temperature_of_Coldest_Month', 'CHELSA_Precipitation_Seasonality', 'CHELSA_Precipitation_of_Coldest_Quarter', 'CHELSA_Precipitation_of_Driest_Month', 'CHELSA_Precipitation_of_Driest_Quarter', 'CHELSA_Precipitation_of_Warmest_Quarter', 'CHELSA_Precipitation_of_Wettest_Month', 'CHELSA_Precipitation_of_Wettest_Quarter', 'CHELSA_Temperature_Annual_Range', 'CHELSA_Temperature_Seasonality', 'Depth_to_Water_Table', 'EarthEnvTopoMed_Eastness', 'EarthEnvTopoMed_Elevation', 'EarthEnvTopoMed_Northness', 'EarthEnvTopoMed_ProfileCurvature', 'EarthEnvTopoMed_Roughness', 'EarthEnvTopoMed_Slope', 'SG_Absolute_depth_to_bedrock', 'WorldClim2_SolarRadiation_AnnualMean', 'WorldClim2_WindSpeed_AnnualMean', 'EarthEnvCloudCover_MODCF_interannualSD', 'EarthEnvCloudCover_MODCF_intraannualSD', 'EarthEnvCloudCover_MODCF_meanannual', 'EarthEnvTopoMed_AspectCosine', 'EarthEnvTopoMed_AspectSine', 'SG_Clay_Content_0_100cm', 'SG_Coarse_fragments_0_100cm', 'SG_Sand_Content_0_100cm', 'SG_Silt_Content_0_100cm', 'SG_Soil_pH_H2O_0_100cm', 'PresentTreeCover']\n"
     ]
    }
   ],
   "source": [
    "# define the list of predictors\n",
    "propertyOfInterest = ['Aridity_Index',\n",
    "                      'CHELSA_Annual_Mean_Temperature',\n",
    "                      'CHELSA_Annual_Precipitation',\n",
    "                      'CHELSA_Isothermality',\n",
    "                      'CHELSA_Max_Temperature_of_Warmest_Month',\n",
    "                      'CHELSA_Mean_Diurnal_Range',\n",
    "                      'CHELSA_Mean_Temperature_of_Coldest_Quarter',\n",
    "                      'CHELSA_Mean_Temperature_of_Driest_Quarter',\n",
    "                      'CHELSA_Mean_Temperature_of_Warmest_Quarter',\n",
    "                      'CHELSA_Mean_Temperature_of_Wettest_Quarter',\n",
    "                      'CHELSA_Min_Temperature_of_Coldest_Month',\n",
    "                      'CHELSA_Precipitation_Seasonality',\n",
    "                      'CHELSA_Precipitation_of_Coldest_Quarter',\n",
    "                      'CHELSA_Precipitation_of_Driest_Month',\n",
    "                      'CHELSA_Precipitation_of_Driest_Quarter',\n",
    "                      'CHELSA_Precipitation_of_Warmest_Quarter',\n",
    "                      'CHELSA_Precipitation_of_Wettest_Month',\n",
    "                      'CHELSA_Precipitation_of_Wettest_Quarter',\n",
    "                      'CHELSA_Temperature_Annual_Range',\n",
    "                      'CHELSA_Temperature_Seasonality',\n",
    "                      'Depth_to_Water_Table',\n",
    "                      'EarthEnvTopoMed_Eastness',\n",
    "                      'EarthEnvTopoMed_Elevation',\n",
    "                      'EarthEnvTopoMed_Northness',\n",
    "                      'EarthEnvTopoMed_ProfileCurvature',\n",
    "                      'EarthEnvTopoMed_Roughness',\n",
    "                      'EarthEnvTopoMed_Slope',\n",
    "                      'SG_Absolute_depth_to_bedrock',\n",
    "                      'WorldClim2_SolarRadiation_AnnualMean',\n",
    "                      'WorldClim2_WindSpeed_AnnualMean',\n",
    "                      'EarthEnvCloudCover_MODCF_interannualSD',\n",
    "                      'EarthEnvCloudCover_MODCF_intraannualSD',\n",
    "                      'EarthEnvCloudCover_MODCF_meanannual',\n",
    "                      'EarthEnvTopoMed_AspectCosine',\n",
    "                      'EarthEnvTopoMed_AspectSine',\n",
    "                      'SG_Clay_Content_0_100cm',\n",
    "                      'SG_Coarse_fragments_0_100cm',\n",
    "                      'SG_Sand_Content_0_100cm',\n",
    "                      'SG_Silt_Content_0_100cm',\n",
    "                      'SG_Soil_pH_H2O_0_100cm',\n",
    "                      'PresentTreeCover'] #\n",
    "print(propertyOfInterest)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Composite Band Names: ['Aridity_Index', 'CHELSA_Annual_Mean_Temperature', 'CHELSA_Annual_Precipitation', 'CHELSA_Isothermality', 'CHELSA_Max_Temperature_of_Warmest_Month', 'CHELSA_Mean_Diurnal_Range', 'CHELSA_Mean_Temperature_of_Coldest_Quarter', 'CHELSA_Mean_Temperature_of_Driest_Quarter', 'CHELSA_Mean_Temperature_of_Warmest_Quarter', 'CHELSA_Mean_Temperature_of_Wettest_Quarter', 'CHELSA_Min_Temperature_of_Coldest_Month', 'CHELSA_Precipitation_Seasonality', 'CHELSA_Precipitation_of_Coldest_Quarter', 'CHELSA_Precipitation_of_Driest_Month', 'CHELSA_Precipitation_of_Driest_Quarter', 'CHELSA_Precipitation_of_Warmest_Quarter', 'CHELSA_Precipitation_of_Wettest_Month', 'CHELSA_Precipitation_of_Wettest_Quarter', 'CHELSA_Temperature_Annual_Range', 'CHELSA_Temperature_Seasonality', 'Depth_to_Water_Table', 'EarthEnvTopoMed_Eastness', 'EarthEnvTopoMed_Elevation', 'EarthEnvTopoMed_Northness', 'EarthEnvTopoMed_ProfileCurvature', 'EarthEnvTopoMed_Roughness', 'EarthEnvTopoMed_Slope', 'SG_Absolute_depth_to_bedrock', 'WorldClim2_SolarRadiation_AnnualMean', 'WorldClim2_WindSpeed_AnnualMean', 'EarthEnvCloudCover_MODCF_interannualSD', 'EarthEnvCloudCover_MODCF_intraannualSD', 'EarthEnvCloudCover_MODCF_meanannual', 'EarthEnvTopoMed_AspectCosine', 'EarthEnvTopoMed_AspectSine', 'SG_Clay_Content_0_100cm', 'SG_Coarse_fragments_0_100cm', 'SG_Sand_Content_0_100cm', 'SG_Silt_Content_0_100cm', 'SG_Soil_pH_H2O_0_100cm', 'PresentTreeCover', 'SpawnDensity']\n"
     ]
    }
   ],
   "source": [
    "# read the composite\n",
    "compositeImage = ee.Image(\"users/leonidmoore/ForestBiomass/20200915_Forest_Biomass_Predictors_Image\").select(propertyOfInterest).addBands(biomassDensityMap)\n",
    "# show the band names of the composite image \n",
    "print('Composite Band Names:',compositeImage.bandNames().getInfo())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STEP 2 Subsampling and Covariates extraction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.1 Export to Google earth engine"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m\u001b[34mThe seeds are:\u001b[0m [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]\n",
      "\u001b[1m\u001b[34mModel is running!\u001b[0m\n",
      "3980\n",
      "3989\n",
      "3999\n",
      "3988\n",
      "3981\n",
      "3982\n",
      "3992\n",
      "3989\n",
      "3980\n",
      "3973\n",
      "3990\n",
      "3994\n",
      "3990\n",
      "3995\n",
      "3980\n",
      "3994\n",
      "3983\n",
      "3989\n",
      "3998\n",
      "3993\n",
      "3987\n",
      "3995\n",
      "3988\n",
      "3994\n",
      "3979\n",
      "3992\n",
      "3975\n",
      "3984\n",
      "4005\n",
      "4006\n",
      "3995\n",
      "3995\n",
      "3997\n",
      "3994\n",
      "3987\n",
      "3992\n",
      "3998\n",
      "3998\n",
      "3993\n",
      "3984\n",
      "3986\n",
      "3988\n",
      "4003\n",
      "3995\n",
      "3978\n",
      "3982\n",
      "3994\n",
      "3989\n",
      "3992\n",
      "3988\n",
      "3978\n",
      "3993\n",
      "3984\n",
      "3987\n",
      "3976\n",
      "3989\n",
      "3992\n",
      "3990\n",
      "4004\n",
      "3998\n",
      "3984\n",
      "3989\n",
      "3980\n",
      "3994\n",
      "3991\n",
      "3986\n",
      "3996\n",
      "3978\n",
      "3991\n",
      "3984\n",
      "4001\n",
      "3986\n",
      "3988\n",
      "3994\n",
      "4000\n",
      "3992\n",
      "3997\n",
      "3986\n",
      "3990\n",
      "3984\n",
      "3975\n",
      "3999\n",
      "3981\n",
      "3993\n",
      "3967\n",
      "3983\n",
      "3987\n",
      "3980\n",
      "4000\n",
      "3990\n",
      "3988\n",
      "4002\n",
      "3994\n",
      "3995\n",
      "3988\n",
      "3990\n",
      "3987\n",
      "4001\n",
      "3990\n",
      "3987\n"
     ]
    }
   ],
   "source": [
    "# define a seed list\n",
    "seedList = np.arange(0, 100, 1).tolist()\n",
    "print(colored('The seeds are:', 'blue', attrs=['bold']),seedList)\n",
    "print(colored('Model is running!', 'blue', attrs=['bold']))\n",
    "for seed in seedList:\n",
    "    # add a random column into the feature collection\n",
    "    # fullRandomPointsWithRandomCol = fullRandomPoints.randomColumn(columnName ='rd', seed=seed)\n",
    "    # filterSubSamplePoints = fullRandomPointsWithRandomCol.filterMetadata(name='rd', operator='less_than', value=0.2)\n",
    "    # print(filterSubSamplePoints.size().getInfo())\n",
    "    # extract covariates\n",
    "    filterSubSamplePoints = ee.FeatureCollection(\"users/leonidmoore/ForestBiomass/SpawnMap/GridSampleShapefiles/HM2_Gridsubsampled_Natural_Seed_\"+str(seed))\n",
    "    randomSubampleWithCovariatesRaw = compositeImage.reduceRegions(collection=filterSubSamplePoints,reducer = ee.Reducer.first())\n",
    "    # remove the observations with NA\n",
    "    subampleWithCovariates = randomSubampleWithCovariatesRaw.filter(ee.Filter.notNull(compositeImage.bandNames()))\n",
    "    # add the random column with the name 'CV_fold'\n",
    "    subampleWithCovariatesAndFold = subampleWithCovariates.randomColumn('CV_Fold',seed).map(lambda f: f.set('CV_Fold',ee.Number(f.get('CV_Fold')).multiply(10).toInt()))\n",
    "    print(subampleWithCovariatesAndFold.size().getInfo())\n",
    "    trainTableWithCovarites_Export = ee.batch.Export.table.toAsset(\n",
    "        collection = subampleWithCovariatesAndFold,\n",
    "        description = 'Train_Table_seed_'+str(seed)+'_Exportation',\n",
    "        assetId = 'users/leonidmoore/ForestBiomass/SpawnMap/TrainTables/HM2_Grid_subsampled_Natural_Train_Table_seed_'+str(seed))\n",
    "    \n",
    "    # start the exportation\n",
    "    trainTableWithCovarites_Export.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STEP 3 Grid search"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### function defining"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# generate the classifier list based on fullParameterSpace\n",
    "def classifierListsGenerator (paramterSets, randomDiscrete = True, randomNumber = 12,nTrees = 20,modelType = 'REGRESSION',bagFraction=0.632,Seed=0):\n",
    "    # define an empty list to load the defined models for grid search\n",
    "    classifierList = []\n",
    "    if randomDiscrete:\n",
    "        # check the randomNumber\n",
    "        if randomNumber is None:\n",
    "            print('Warning! an integer number needs to be allocated to <randomNumber>!')\n",
    "        else:\n",
    "            print('A randomDiscrete approach has been applied to do grid search the paramter space! \\n  The random model number is: '+str(randomNumber)+' !')\n",
    "            # subset the fullParameterSpace randomly with the randomNumber\n",
    "            random.seed(Seed)\n",
    "            randomParameterApplied = random.sample(paramterSets,randomNumber)\n",
    "            # print(randomSubsetParameter)\n",
    "            \n",
    "    else:\n",
    "        print('The full space of the parameter sets is being running for grid search')\n",
    "        random.seed(Seed)\n",
    "        randomParameterApplied = sample(paramterSets,randomNumber)\n",
    "    \n",
    "    print(Seed)\n",
    "    print('function use 20 as the default nTrees, \\n You can define you own nTree value in the function argument settings!')\n",
    "    # loop through the randomParameterApplied\n",
    "    for ParaSet in randomParameterApplied:\n",
    "        model_name = 'GridSeach_Model_'+str(ParaSet[0])+'_'+str(ParaSet[1])+'_'+str(ParaSet[2])\n",
    "        # define the paramter setting of each model in the grid seach and allocate those parameters into the feature\n",
    "        perRF = ee.Feature(ee.Geometry.Point([0,0])).set('ModelName',model_name,'PerClassifier',ee.Classifier.smileRandomForest(\n",
    "            # the default ntrees we use 100\n",
    "            numberOfTrees=nTrees,\n",
    "            variablesPerSplit = ParaSet[0],\n",
    "            minLeafPopulation = ParaSet[1],\n",
    "            maxNodes = ParaSet[2],\n",
    "            bagFraction=bagFraction).setOutputMode(modelType))\n",
    "        classifierList.append(perRF)\n",
    "    return(classifierList)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define the R^2 function for use with continuous valued models (i.e., regression based models)\n",
    "def coefficientOfDetermination(anyVariableTable,propertyOfInterest,propertyOfInterest_Predicted):\n",
    "    # Compute the mean of the property of interest\n",
    "    propertyOfInterestMean = ee.Number(ee.Dictionary(ee.FeatureCollection(anyVariableTable).select([propertyOfInterest]).reduceColumns(ee.Reducer.mean(),[propertyOfInterest])).get('mean'));\n",
    "    # Compute the total sum of squares\n",
    "    def totalSoSFunction(f):\n",
    "        return f.set('Difference_Squared',ee.Number(ee.Feature(f).get(propertyOfInterest)).subtract(propertyOfInterestMean).pow(ee.Number(2)))\n",
    "    totalSumOfSquares = ee.Number(ee.Dictionary(ee.FeatureCollection(anyVariableTable).map(totalSoSFunction).select(['Difference_Squared']).reduceColumns(ee.Reducer.sum(),['Difference_Squared'])).get('sum'))\n",
    "    # Compute the residual sum of squares\n",
    "    def residualSoSFunction(f):\n",
    "        return f.set('Residual_Squared',ee.Number(ee.Feature(f).get(propertyOfInterest)).subtract(ee.Number(ee.Feature(f).get(propertyOfInterest_Predicted))).pow(ee.Number(2)))\n",
    "    residualSumOfSquares = ee.Number(ee.Dictionary(ee.FeatureCollection(anyVariableTable).map(residualSoSFunction).select(['Residual_Squared']).reduceColumns(ee.Reducer.sum(),['Residual_Squared'])).get('sum'))\n",
    "    # Finalize the calculation\n",
    "    r2 = ee.Number(1).subtract(residualSumOfSquares.divide(totalSumOfSquares))\n",
    "    # print('I am running as well!')\n",
    "\n",
    "    return ee.Number(r2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define a function to take a feature with a classifier of interest\n",
    "def computeCVAccuracy(featureWithClassifier,\n",
    "                      propertyOfInterest,\n",
    "                      modelType,\n",
    "                      kFoldAssignmentFC,\n",
    "                      cvFoldString,\n",
    "                      classProperty,\n",
    "                      accuracyMetricString,\n",
    "                      extractedVariableTable):\n",
    "    # Pull the classifier from the feature\n",
    "    cOI = ee.Classifier(featureWithClassifier.get('PerClassifier'))\n",
    "    # Create a function to map through the fold assignments and compute the overall accuracy\n",
    "    # for all validation folds\n",
    "    def computeAccuracyForFold(foldFeature):\n",
    "        # Organize the training and validation data\n",
    "        foldNumber = ee.Number(ee.Feature(foldFeature).get('Fold'))\n",
    "        # print(foldNumber.getInfo())\n",
    "        trainingData = extractedVariableTable.filterMetadata(cvFoldString,'not_equals',foldNumber)\n",
    "        # print(trainingData.first().getInfo())\n",
    "        validationData = extractedVariableTable.filterMetadata(cvFoldString,'equals',foldNumber)\n",
    "        # Train the classifier and classify the validation dataset\n",
    "        trainedClassifier = cOI.train(trainingData,classProperty,propertyOfInterest)\n",
    "        outputtedPropName = classProperty+'_Predicted'\n",
    "        classifiedValidationData = validationData.classify(trainedClassifier,outputtedPropName)\n",
    "        # Create a central if/then statement that determines the type of accuracy values that are returned\n",
    "        if modelType == 'CLASSIFICATION':\n",
    "            # Compute the overall accuracy of the classification\n",
    "            errorMatrix = classifiedValidationData.errorMatrix(classProperty,outputtedPropName,categoricalLevels)\n",
    "            overallAccuracy = ee.Number(errorMatrix.accuracy())\n",
    "            return foldFeature.set(accuracyMetricString,overallAccuracy)\n",
    "        else:\n",
    "            # Compute the R^2 of the regression\n",
    "            r2ToSet = coefficientOfDetermination(classifiedValidationData,classProperty,outputtedPropName)\n",
    "            return foldFeature.set(accuracyMetricString,r2ToSet)\n",
    "\n",
    "    # Compute the accuracy values of the classifier across all folds\n",
    "    accuracyFC = kFoldAssignmentFC.map(computeAccuracyForFold)\n",
    "    meanAccuracy = accuracyFC.aggregate_mean(accuracyMetricString)\n",
    "    tsdAccuracy = accuracyFC.aggregate_total_sd(accuracyMetricString)\n",
    "    # print('I am running!')\n",
    "    # Compute the feature to return\n",
    "    featureToReturn = featureWithClassifier.select(['ModelName']).set('Mean_'+accuracyMetricString,meanAccuracy,'StDev_'+accuracyMetricString,tsdAccuracy)\n",
    "    return featureToReturn"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "def gridSearchEarthEngine(inputTrainTable,# train data table in ee.FeatureCollection format\n",
    "                          propertyOfInterest = propertyOfInterest, # list of predictors\n",
    "                          classProperty = 'lgBD', # response varibale name in Google earth engine\n",
    "                          nTrees = 20, # number of trees, default is 100\n",
    "                          variablesPerSplitList = np.arange(3, 24, 3).tolist(), # list\n",
    "                          minLeafPopulationList = np.arange(2, 22, 2).tolist(), # list\n",
    "                          maxNodesList = np.arange(10, 110, 10).tolist(),# list\n",
    "                          bagFraction = 0.632,\n",
    "                          randomDiscrete = True, #boolean\n",
    "                          randomNumber = 1, # if random discrete is True, you must set this value\n",
    "                          foldsValue = 10,\n",
    "                          modelType = 'REGRESSION',\n",
    "                          cvFoldString = 'CV_Fold',\n",
    "                          pyramidingPolicy = 'mean',\n",
    "                          accuracyMetricString = 'R2',\n",
    "                          Seeds = 0):\n",
    "    \n",
    "    parameterLists = [variablesPerSplitList,minLeafPopulationList,maxNodesList]\n",
    "    # generate the list of all the possible paramter set combinations\n",
    "    fullParamterSpace = list(itertools.product(*parameterLists))\n",
    "    # generate the classifer in featureColletion format\n",
    "    classifierList = classifierListsGenerator(paramterSets = fullParamterSpace,\n",
    "                                              randomNumber = randomNumber,\n",
    "                                              nTrees = nTrees,\n",
    "                                              bagFraction = 0.632,\n",
    "                                              Seed=Seeds)\n",
    "    \n",
    "    kList = list(range(0,foldsValue))\n",
    "    kFoldAssignmentFC = ee.FeatureCollection(ee.List(kList).map(lambda n: ee.Feature(ee.Geometry.Point([0,0])).set('Fold',n)))\n",
    "    # print(kFoldAssignmentFC.getInfo())\n",
    "    classDf = pd.DataFrame(columns = ['Mean_R2','StDev_R2','ModelName','numberOfTrees','variablesPerSplit','minLeafPopulation','bagFraction','maxNodes'])\n",
    "\n",
    "    for rf in classifierList:\n",
    "        # print(rf.getInfo())\n",
    "        accuracy_feature = ee.Feature(computeCVAccuracy(rf,propertyOfInterest,modelType='REGRESSION',kFoldAssignmentFC= kFoldAssignmentFC,cvFoldString = cvFoldString,classProperty=classProperty,accuracyMetricString =accuracyMetricString,extractedVariableTable = inputTrainTable))\n",
    "        # extract the parameter information\n",
    "        parameterDict = rf.getInfo().get('properties',{}).get('PerClassifier').get('classifier',{})\n",
    "        parameterDF = pd.DataFrame(parameterDict,index = [0])\n",
    "        # extract the metrics information\n",
    "        metricDict = accuracy_feature.getInfo().get('properties')\n",
    "        metricDF = pd.DataFrame(metricDict,index = [0])\n",
    "\n",
    "        # print(metricDF)\n",
    "        # print(parameterDF)\n",
    "        resultDF = pd.concat([metricDF, parameterDF], axis=1, sort=False)\n",
    "        # print(resultDF)\n",
    "        classDf = pd.concat([classDf,resultDF],sort=False)# classDf.append(resultDF, sort=False)#\n",
    "    # sort the grid search result by descending of Mean_R2\n",
    "    classDfSorted = classDf.sort_values(['Mean_R2'], ascending = False)\n",
    "\n",
    "    # print('Top 5 grid search results:\\n', classDfSorted.head(5))\n",
    "    return(classDfSorted.head(1)) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m\u001b[34mThe seeds are:\u001b[0m [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]\n",
      "\u001b[1m\u001b[34mModel is running!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "9\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:9 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "10\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:10 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "11\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:11 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "12\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:12 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "13\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:13 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "14\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:14 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "15\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:15 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "16\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:16 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "17\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:17 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "18\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:18 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "19\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:19 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "20\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:20 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "21\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:21 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "22\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:22 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "23\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:23 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "24\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:24 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "25\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:25 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "26\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:26 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "27\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:27 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "28\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:28 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "29\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:29 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "30\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:30 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "31\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:31 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "32\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:32 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "33\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:33 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "34\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:34 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "35\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:35 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "36\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:36 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "37\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m\u001b[34mGrid search for seed:37 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "38\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:38 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "39\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:39 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "40\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:40 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "41\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:41 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "42\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:42 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "43\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:43 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "44\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:44 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "45\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:45 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "46\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:46 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "47\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:47 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "48\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:48 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "49\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:49 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "50\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:50 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "51\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:51 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "52\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:52 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "53\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:53 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "54\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:54 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "55\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:55 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "56\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:56 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "57\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:57 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "58\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:58 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "59\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:59 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "60\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:60 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "61\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:61 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "62\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:62 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "63\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:63 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "64\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:64 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "65\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:65 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "66\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:66 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "67\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m\u001b[34mGrid search for seed:67 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "68\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:68 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "69\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:69 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "70\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:70 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "71\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:71 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "72\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:72 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "73\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:73 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "74\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:74 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "75\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:75 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "76\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:76 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "77\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:77 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "78\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:78 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "79\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:79 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "80\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:80 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "81\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:81 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "82\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:82 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "83\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:83 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "84\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:84 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "85\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:85 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "86\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:86 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "87\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:87 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "88\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:88 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "89\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:89 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "90\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:90 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "91\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:91 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "92\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:92 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "93\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:93 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "94\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:94 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "95\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:95 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "96\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:96 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "97\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m\u001b[34mGrid search for seed:97 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "98\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:98 is done!\u001b[0m\n",
      "A randomDiscrete approach has been applied to do grid search the paramter space! \n",
      "  The random model number is: 48 !\n",
      "99\n",
      "function use 20 as the default nTrees, \n",
      " You can define you own nTree value in the function argument settings!\n",
      "\u001b[1m\u001b[34mGrid search for seed:99 is done!\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "# generate a ee.List to save the seeds\n",
    "seedList = np.arange(9, 100, 1).tolist()\n",
    "print(colored('The seeds are:', 'blue', attrs=['bold']),seedList)\n",
    "print(colored('Model is running!', 'blue', attrs=['bold']))\n",
    "for seed in seedList:\n",
    "    # load the traindata table for each subsample\n",
    "    inputVariableTable = ee.FeatureCollection('users/leonidmoore/ForestBiomass/SpawnMap/TrainTables/HM2_Grid_subsampled_Natural_Train_Table_seed_'+str(seed))\n",
    "    # check the information of the FeatureCollection with predictors and covariates\n",
    "    # print(nullExcludedTable.first().getInfo())\n",
    "    # print(inputVariableTable.limit(1).getInfo())\n",
    "    topModelParameter = gridSearchEarthEngine(inputTrainTable = inputVariableTable,\n",
    "                                              propertyOfInterest = propertyOfInterest,\n",
    "                                              classProperty = 'SpawnDensity',\n",
    "                                              randomNumber = 48,\n",
    "                                              nTrees = 200,\n",
    "                                              Seeds=seed)\n",
    "    # write the top parameters table to local folder\n",
    "    # topModelParameter.to_csv('RemoteSensingModel/GridSearchResult/SD2_Potential_Biomass_Modeling_Grid_Search_Seed_'+str(seed)+'.csv',header=True,mode='w+')\n",
    "    topModelParameter.to_csv('Data/SatelliteDerivedModel/GridSearchResult/HM2_Grid_subsampled_Natural_Potential_Biomass_Modeling_Grid_Search_Seed_'+str(seed)+'.csv',header=True,mode='w+')\n",
    "    # show the progress for the grid seach by the seed number\n",
    "    print(colored('Grid search for seed:'+str(seed)+' is done!', 'blue', attrs=['bold']))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STEP 4 Potential biomass mapping"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.1 Prepare the toggled composite"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# load the potential tree cover and rename it to 'PresentTreeCover'\n",
    "potentialTreeCover = ee.Image('users/leonidmoore/ForestBiomass/Bastin_et_al_2019_Potential_Forest_Cover_Adjusted').rename(\"PresentTreeCover\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['Aridity_Index', 'CHELSA_Annual_Mean_Temperature', 'CHELSA_Annual_Precipitation', 'CHELSA_Isothermality', 'CHELSA_Max_Temperature_of_Warmest_Month']\n"
     ]
    }
   ],
   "source": [
    "# define the list of retained predictors\n",
    "retainedPropeties = ['Aridity_Index',\n",
    "                      'CHELSA_Annual_Mean_Temperature',\n",
    "                      'CHELSA_Annual_Precipitation',\n",
    "                      'CHELSA_Isothermality',\n",
    "                      'CHELSA_Max_Temperature_of_Warmest_Month',\n",
    "                      'CHELSA_Mean_Diurnal_Range',\n",
    "                      'CHELSA_Mean_Temperature_of_Coldest_Quarter',\n",
    "                      'CHELSA_Mean_Temperature_of_Driest_Quarter',\n",
    "                      'CHELSA_Mean_Temperature_of_Warmest_Quarter',\n",
    "                      'CHELSA_Mean_Temperature_of_Wettest_Quarter',\n",
    "                      'CHELSA_Min_Temperature_of_Coldest_Month',\n",
    "                      'CHELSA_Precipitation_Seasonality',\n",
    "                      'CHELSA_Precipitation_of_Coldest_Quarter',\n",
    "                      'CHELSA_Precipitation_of_Driest_Month',\n",
    "                      'CHELSA_Precipitation_of_Driest_Quarter',\n",
    "                      'CHELSA_Precipitation_of_Warmest_Quarter',\n",
    "                      'CHELSA_Precipitation_of_Wettest_Month',\n",
    "                      'CHELSA_Precipitation_of_Wettest_Quarter',\n",
    "                      'CHELSA_Temperature_Annual_Range',\n",
    "                      'CHELSA_Temperature_Seasonality',\n",
    "                      'Depth_to_Water_Table',\n",
    "                      'EarthEnvTopoMed_Eastness',\n",
    "                      'EarthEnvTopoMed_Elevation',\n",
    "                      'EarthEnvTopoMed_Northness',\n",
    "                      'EarthEnvTopoMed_ProfileCurvature',\n",
    "                      'EarthEnvTopoMed_Roughness',\n",
    "                      'EarthEnvTopoMed_Slope',\n",
    "                      'SG_Absolute_depth_to_bedrock',\n",
    "                      'WorldClim2_SolarRadiation_AnnualMean',\n",
    "                      'WorldClim2_WindSpeed_AnnualMean',\n",
    "                      'EarthEnvCloudCover_MODCF_interannualSD',\n",
    "                      'EarthEnvCloudCover_MODCF_intraannualSD',\n",
    "                      'EarthEnvCloudCover_MODCF_meanannual',\n",
    "                      'EarthEnvTopoMed_AspectCosine',\n",
    "                      'EarthEnvTopoMed_AspectSine',\n",
    "                      'SG_Clay_Content_0_100cm',\n",
    "                      'SG_Coarse_fragments_0_100cm',\n",
    "                      'SG_Sand_Content_0_100cm',\n",
    "                      'SG_Silt_Content_0_100cm',\n",
    "                      'SG_Soil_pH_H2O_0_100cm']\n",
    "print(retainedPropeties[0:5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m\u001b[34mThe band names are:\u001b[0m ['Aridity_Index', 'CHELSA_Annual_Mean_Temperature', 'CHELSA_Annual_Precipitation', 'CHELSA_Isothermality', 'CHELSA_Max_Temperature_of_Warmest_Month', 'CHELSA_Mean_Diurnal_Range', 'CHELSA_Mean_Temperature_of_Coldest_Quarter', 'CHELSA_Mean_Temperature_of_Driest_Quarter', 'CHELSA_Mean_Temperature_of_Warmest_Quarter', 'CHELSA_Mean_Temperature_of_Wettest_Quarter', 'CHELSA_Min_Temperature_of_Coldest_Month', 'CHELSA_Precipitation_Seasonality', 'CHELSA_Precipitation_of_Coldest_Quarter', 'CHELSA_Precipitation_of_Driest_Month', 'CHELSA_Precipitation_of_Driest_Quarter', 'CHELSA_Precipitation_of_Warmest_Quarter', 'CHELSA_Precipitation_of_Wettest_Month', 'CHELSA_Precipitation_of_Wettest_Quarter', 'CHELSA_Temperature_Annual_Range', 'CHELSA_Temperature_Seasonality', 'Depth_to_Water_Table', 'EarthEnvTopoMed_Eastness', 'EarthEnvTopoMed_Elevation', 'EarthEnvTopoMed_Northness', 'EarthEnvTopoMed_ProfileCurvature', 'EarthEnvTopoMed_Roughness', 'EarthEnvTopoMed_Slope', 'SG_Absolute_depth_to_bedrock', 'WorldClim2_SolarRadiation_AnnualMean', 'WorldClim2_WindSpeed_AnnualMean', 'EarthEnvCloudCover_MODCF_interannualSD', 'EarthEnvCloudCover_MODCF_intraannualSD', 'EarthEnvCloudCover_MODCF_meanannual', 'EarthEnvTopoMed_AspectCosine', 'EarthEnvTopoMed_AspectSine', 'SG_Clay_Content_0_100cm', 'SG_Coarse_fragments_0_100cm', 'SG_Sand_Content_0_100cm', 'SG_Silt_Content_0_100cm', 'SG_Soil_pH_H2O_0_100cm', 'PresentTreeCover']\n"
     ]
    }
   ],
   "source": [
    "# replace the human activity layers in the compositeImageRaw\n",
    "compositeImageUpdated = compositeImage.select(retainedPropeties).addBands(potentialTreeCover)\n",
    "# present the composite band names\n",
    "print(colored('The band names are:', 'blue', attrs=['bold']),compositeImageUpdated.bandNames().getInfo())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.2 Machine learning mapping for all scalers (SD2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m\u001b[34mThe models are:\u001b[0m [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]\n",
      "\u001b[1m\u001b[34mModel is running:\n",
      "With paramter sets:\u001b[0m\n",
      "seed 0 15 18 90\n",
      "seed 1 18 14 100\n",
      "seed 2 18 12 80\n",
      "seed 3 21 18 80\n",
      "seed 4 18 10 100\n",
      "seed 5 21 14 80\n",
      "seed 6 21 16 90\n",
      "seed 7 18 16 100\n",
      "seed 8 21 16 90\n",
      "seed 9 18 14 80\n",
      "seed 10 21 14 100\n",
      "seed 11 21 14 100\n",
      "seed 12 21 12 90\n",
      "seed 13 15 12 100\n",
      "seed 14 21 16 100\n",
      "seed 15 18 16 90\n",
      "seed 16 21 12 90\n",
      "seed 17 21 16 80\n",
      "seed 18 15 12 100\n",
      "seed 19 18 20 90\n",
      "seed 20 21 20 80\n",
      "seed 21 18 20 100\n",
      "seed 22 18 16 100\n",
      "seed 23 18 16 100\n",
      "seed 24 21 20 90\n",
      "seed 25 21 8 100\n",
      "seed 26 21 12 100\n",
      "seed 27 21 14 100\n",
      "seed 28 21 16 90\n",
      "seed 29 21 14 80\n",
      "seed 30 21 14 100\n",
      "seed 31 21 16 90\n",
      "seed 32 18 14 90\n",
      "seed 33 21 14 100\n",
      "seed 34 18 10 90\n",
      "seed 35 21 14 90\n",
      "seed 36 21 14 90\n",
      "seed 37 21 10 100\n",
      "seed 38 18 10 100\n",
      "seed 39 18 16 90\n",
      "seed 40 15 14 100\n",
      "seed 41 18 14 90\n",
      "seed 42 18 10 100\n",
      "seed 43 21 18 80\n",
      "seed 44 21 10 100\n",
      "seed 45 21 12 90\n",
      "seed 46 21 10 100\n",
      "seed 47 18 12 100\n",
      "seed 48 18 14 100\n",
      "seed 49 18 12 100\n",
      "seed 50 21 12 90\n",
      "seed 51 15 12 100\n",
      "seed 52 21 18 80\n",
      "seed 53 15 10 100\n",
      "seed 54 18 14 100\n",
      "seed 55 21 12 100\n",
      "seed 56 21 14 90\n",
      "seed 57 18 12 100\n",
      "seed 58 15 12 100\n",
      "seed 59 18 10 90\n",
      "seed 60 18 12 100\n",
      "seed 61 21 6 100\n",
      "seed 62 18 12 90\n",
      "seed 63 21 18 100\n",
      "seed 64 21 14 90\n",
      "seed 65 21 14 90\n",
      "seed 66 15 16 100\n",
      "seed 67 21 12 100\n",
      "seed 68 18 12 90\n",
      "seed 69 21 16 70\n",
      "seed 70 18 10 100\n",
      "seed 71 21 16 100\n",
      "seed 72 21 10 90\n",
      "seed 73 18 16 80\n",
      "seed 74 21 16 100\n",
      "seed 75 21 18 100\n",
      "seed 76 21 10 100\n",
      "seed 77 18 14 100\n",
      "seed 78 21 12 100\n",
      "seed 79 15 14 90\n",
      "seed 80 18 16 70\n",
      "seed 81 15 12 100\n",
      "seed 82 21 16 80\n",
      "seed 83 18 18 80\n",
      "seed 84 21 16 80\n",
      "seed 85 18 16 100\n",
      "seed 86 18 14 100\n",
      "seed 87 21 14 100\n",
      "seed 88 18 8 100\n",
      "seed 89 21 20 80\n",
      "seed 90 18 12 100\n",
      "seed 91 21 12 100\n",
      "seed 92 21 10 90\n",
      "seed 93 18 16 100\n",
      "seed 94 21 12 100\n",
      "seed 95 21 12 90\n",
      "seed 96 21 12 90\n",
      "seed 97 21 18 90\n",
      "seed 98 18 14 100\n",
      "seed 99 21 20 90\n"
     ]
    }
   ],
   "source": [
    "# define a loop through the seed list\n",
    "seedList = np.arange(0, 100, 1).tolist()\n",
    "# define the dependent variables list\n",
    "print(colored('The models are:', 'blue', attrs=['bold']),seedList)\n",
    "print(colored('Model is running:\\nWith paramter sets:', 'blue', attrs=['bold']))\n",
    "# for seed in seedList: range(0,len(seedList))\n",
    "for seed in seedList:\n",
    "    # load the points data with the covariates\n",
    "    trainTable = ee.FeatureCollection('users/leonidmoore/ForestBiomass/SpawnMap/TrainTables/HM2_Grid_subsampled_Natural_Train_Table_seed_'+str(seed))\n",
    "    # print(trainTable.size().getInfo())\n",
    "    parameterTable = pd.read_csv('Data/SatelliteDerivedModel/GridSearchResult/HM2_Grid_subsampled_Natural_Potential_Biomass_Modeling_Grid_Search_Seed_'+str(seed)+'.csv', float_precision='round_trip')\n",
    "    # not recomend to run the code below\n",
    "    # print(parameterTable.head())\n",
    "    # extract the paramters\n",
    "    variablesPerSplitVal = int(parameterTable['variablesPerSplit'].iat[0]) # mtry\n",
    "    minLeafPopulationVal = int(parameterTable['minLeafPopulation'].iat[0]) # minrow\n",
    "    maxNodesVal = int(parameterTable['maxNodes'].iat[0]) # mac depth\n",
    "    print('seed',seed,variablesPerSplitVal,minLeafPopulationVal,maxNodesVal)\n",
    "    # define the random forest classifier\n",
    "    rfClassifier = ee.Classifier.smileRandomForest(numberOfTrees = 200,\n",
    "                                                   variablesPerSplit = variablesPerSplitVal, # mtry\n",
    "                                                   minLeafPopulation = minLeafPopulationVal, # minrow\n",
    "                                                   maxNodes = maxNodesVal, # max depth\n",
    "                                                   bagFraction = 0.632,\n",
    "                                                   seed = seed).setOutputMode('REGRESSION')\n",
    "    trainedClassifier = rfClassifier.train(features = trainTable,\n",
    "                                           classProperty = 'SpawnDensity',\n",
    "                                           inputProperties = propertyOfInterest)\n",
    "    # execute the prediction to generate the map\n",
    "    existingCarbonDensityMap = compositeImageUpdated.classify(trainedClassifier)\n",
    "    # print(predictedWoodDensityMap.getInfo())\n",
    "    predictionExport = ee.batch.Export.image.toAsset(image = existingCarbonDensityMap,\n",
    "                                                     description = '20221108_HM2_Potential_Biomass_Density_Map_To_Asset_'+str(seed),\n",
    "                                                     assetId = 'users/leonidmoore/ForestBiomass/SpawnMap/PredictedMaps/Predicted_HM2_Potential_Biomass_Map_with_Seed_'+str(seed),\n",
    "                                                     region = unboundedGeo,\n",
    "                                                     crs = 'EPSG:4326',\n",
    "                                                     crsTransform = [0.008333333333333333,0,-180,0,-0.008333333333333333,90],\n",
    "                                                     maxPixels = 1e13)\n",
    "\n",
    "    # print(predictionExportAsset)\n",
    "    # start the export task\n",
    "    predictionExport.start()\n",
    "    # show the task status\n",
    "    predictionExport.status()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.3 Stack all potential maps into an Image and export the mean etc. (HM2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m\u001b[34mThe band names are:\u001b[0m ['Model_0', 'Model_1', 'Model_2', 'Model_3', 'Model_4', 'Model_5', 'Model_6', 'Model_7', 'Model_8', 'Model_9', 'Model_10', 'Model_11', 'Model_12', 'Model_13', 'Model_14', 'Model_15', 'Model_16', 'Model_17', 'Model_18', 'Model_19', 'Model_20', 'Model_21', 'Model_22', 'Model_23', 'Model_24', 'Model_25', 'Model_26', 'Model_27', 'Model_28', 'Model_29', 'Model_30', 'Model_31', 'Model_32', 'Model_33', 'Model_34', 'Model_35', 'Model_36', 'Model_37', 'Model_38', 'Model_39', 'Model_40', 'Model_41', 'Model_42', 'Model_43', 'Model_44', 'Model_45', 'Model_46', 'Model_47', 'Model_48', 'Model_49', 'Model_50', 'Model_51', 'Model_52', 'Model_53', 'Model_54', 'Model_55', 'Model_56', 'Model_57', 'Model_58', 'Model_59', 'Model_60', 'Model_61', 'Model_62', 'Model_63', 'Model_64', 'Model_65', 'Model_66', 'Model_67', 'Model_68', 'Model_69', 'Model_70', 'Model_71', 'Model_72', 'Model_73', 'Model_74', 'Model_75', 'Model_76', 'Model_77', 'Model_78', 'Model_79', 'Model_80', 'Model_81', 'Model_82', 'Model_83', 'Model_84', 'Model_85', 'Model_86', 'Model_87', 'Model_88', 'Model_89', 'Model_90', 'Model_91', 'Model_92', 'Model_93', 'Model_94', 'Model_95', 'Model_96', 'Model_97', 'Model_98', 'Model_99']\n",
      "\u001b[1m\u001b[34mExport is running on Google Earth Engine!\n",
      "Please check it on the Google Earth Engine UI.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "# load the images predicted by the ensemble models\n",
    "# define an empty image\n",
    "firstImage = ee.Image('users/leonidmoore/ForestBiomass/SpawnMap/PredictedMaps/Predicted_HM2_Potential_Biomass_Map_with_Seed_0').rename('Model_0').toFloat()\n",
    "# load the other images and add thme as bands to the first image above\n",
    "modelList = np.arange(1, 100, 1).tolist()\n",
    "for ml in modelList:\n",
    "    perModelImage = ee.Image('users/leonidmoore/ForestBiomass/SpawnMap/PredictedMaps/Predicted_HM2_Potential_Biomass_Map_with_Seed_'+str(ml)).rename('Model_'+str(ml)).toFloat()\n",
    "    firstImage = firstImage.addBands(perModelImage)\n",
    "\n",
    "print(colored('The band names are:', 'blue', attrs=['bold']),firstImage.bandNames().getInfo())\n",
    "\n",
    "# calculate the mean and variation images\n",
    "meanImage = firstImage.reduce(ee.Reducer.mean())\n",
    "variImage = firstImage.reduce(ee.Reducer.stdDev()).divide(meanImage)\n",
    "# get the 95% quantile\n",
    "percentileImage = firstImage.reduce(ee.Reducer.percentile([2.5,97.5],['lower','upper']))\n",
    "# add those two images into the GEE assets\n",
    "meanExport = ee.batch.Export.image.toAsset(image = meanImage.toFloat(),\n",
    "                                           description = '20221107_HM2_Potential_Density_Ensemble_Mean_Map_To_Asset',\n",
    "                                           assetId = 'users/leonidmoore/ForestBiomass/GroundSourcedModel/EnsambledMaps/Predicted_HM2_Potential_density_Ensambled_Mean',\n",
    "                                           region = unboundedGeo,\n",
    "                                           crs = 'EPSG:4326',\n",
    "                                           crsTransform = [0.008333333333333333,0,-180,0,-0.008333333333333333,90],\n",
    "                                           maxPixels = 1e13)\n",
    "\n",
    "\n",
    "# start the export task\n",
    "meanExport.start()\n",
    "# show the task status\n",
    "meanExport.status()\n",
    "\n",
    "variExport = ee.batch.Export.image.toAsset(image = variImage.toFloat(),\n",
    "                                           description = '20221107_HM2_Potential_Density_Variation_Coef_Map_To_Asset',\n",
    "                                           assetId = 'users/leonidmoore/ForestBiomass/GroundSourcedModel/EnsambledMaps/Predicted_HM2_Potential_density_Ensambled_Variation_Coefficient',\n",
    "                                           region = unboundedGeo,\n",
    "                                           crs = 'EPSG:4326',\n",
    "                                           crsTransform = [0.008333333333333333,0,-180,0,-0.008333333333333333,90],\n",
    "                                           maxPixels = 1e13)\n",
    "\n",
    "# start the export task\n",
    "variExport.start()\n",
    "# show the task status\n",
    "variExport.status()\n",
    "\n",
    "percentileExport = ee.batch.Export.image.toAsset(image = percentileImage.toFloat(),\n",
    "                                                 description = '20221107_HM2_Potential_Density_Percentile_Map_To_Asset',\n",
    "                                                 assetId = 'users/leonidmoore/ForestBiomass/GroundSourcedModel/EnsambledMaps/Predicted_HM2_Potential_density_Ensambled_Percentile',\n",
    "                                                 region = unboundedGeo,\n",
    "                                                 crs = 'EPSG:4326',\n",
    "                                                 crsTransform = [0.008333333333333333,0,-180,0,-0.008333333333333333,90],\n",
    "                                                 maxPixels = 1e13)\n",
    "\n",
    "# start the export task\n",
    "percentileExport.start()\n",
    "# show the task status\n",
    "percentileExport.status()\n",
    "# PRINT THE INFORMATION THAT THE EXPORT IS RUNNING ON GOOGLE EARTH ENGINE \n",
    "print(colored('Export is running on Google Earth Engine!\\nPlease check it on the Google Earth Engine UI.', 'blue', attrs=['bold']))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
